/* 
 * File:   monitor.c
 * Author: tangchao
 *
 * Created on 2013年6月3日, 下午4:20
 */

#include "m_global.h"
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sybfront.h>
#include <sybdb.h>

/* */

#include "m_mssql.h"
#include "m_redis.h"
#include "m_mysql.h"
#include "m_staff.h"

static void my_help(void);
static void process_redis(NG_THD *thd);
//static NG_THD* new_host(void);

pthread_mutex_t mutex;
int node = -1;

/* list table initialize */
cnf_file *cnf_file_list;


/* global options */
char *m_global_config_file;
char *m_general_config_dir;
short log_level;
char *log_file;
int polling_time;
int max_thread_num;

static void my_help(void)
{
    printf("Usage:\n"
            "[name]\n"
            "host = 192.168.1.1\n"
            "user = root\n"
            "password = test\n"
            "port = 3306\n"
            "database = test\n");

    return;
}

static int m_global_file_parse_one_row(char *src)
{
    int pos = 0, length = 0;
    char key[64];
    char *value;

    length = strlen(src);

    for (pos = 0; pos < length; pos++)
    {
        if (src[pos] == 0x3d)
            break;
    }

    if (pos == 0)
    {
        fprintf(stderr, "global.ini format error: %s.\n", src);
        return 1;
    }

    memset(key, 0, 64);
    strncpy(key, src, pos);
    value = &src[0];
    value += (pos + 1);

    if (!strcmp(key, "configuration_directory"))
    {
        m_general_config_dir = (char *) malloc(strlen(value));
        if (NULL == m_general_config_dir)
            return 1;
        sprintf(m_general_config_dir, "%s", value);
        return 0;
    }

    if (!strcmp(key, "max_thread_number"))
    {
        max_thread_num = atoi(value);
        return 0;
    }

    if (!strcmp(key, "log_level"))
    {
        log_level = atoi(value);
        return 0;
    }

    if (!strcmp(key, "log_file"))
    {
        log_file = (char *) malloc(strlen(value));
        if (NULL == log_file)
            return 1;
        sprintf(log_file, "%s", value);
        return 0;
    }

    if (!strcmp(key, "contact_information"))
    {
        if (read_file_into_list(cnf_file_list, value, CONTACT_MEMBER))
            return 1;
        return 0;
    }

    if (!strcmp(key, "contact_group"))
    {
        if (read_file_into_list(cnf_file_list, value, CONTACT_GROUP))
            return 1;
        return 0;
    }

    if (!strcmp(key, "host_information"))
    {
        if (read_file_into_list(cnf_file_list, value, MONITOR_HOST))
            return 1;
        return 0;
    }

    if (!strcmp(key, "host_group"))
    {
        if (read_file_into_list(cnf_file_list, value, MONITOR_HOST_GROUP))
            return 1;
        return 0;
    }

    if (!strcmp(key, "polling_time"))
    {
        polling_time = atoi(value);
        return 0;
    }

    return 1;
}

static int m_global_file_parse(char *file)
{
    char buff[0x200];
    FILE *fd;

    if (m_access(file))
        return 1;

    fd = fopen(file, "r");

    if (fd == 0)
    {
        fprintf(stderr, "fopen %s error\n", file);
        return 1;
    }

    while (fgets(buff, 0x200, fd))
    {
        if (NULL == strtrim(buff) || 0x23 == buff[0])
            continue;
        if (m_global_file_parse_one_row(buff))
            return 1;
    }
    fclose(fd);
    return node;
}

int process(NG_THD *thd)
{
    int error = 0;
    MYSQL *mysql = NULL, conn;
    MYSQL_RES *res = NULL;
    char *select = "select 1 from ng_monitor_tangchao where id = 1";
    char *update = "update ng_monitor_tangchao set replica = now() where id = 1";
    char *sql_init = "insert into ng_monitor_tangchao(id, replica) values(1, now())";

    mysql = mysql_init(&conn);
    if (NULL == mysql)
    {
        fprintf(stderr, "%s, init connection error.\n", thd->host);
        goto err;
    }
    mysql->reconnect = 1;

    if (!mysql_real_connect(mysql, thd->host, thd->user, thd->pass, thd->db, thd->port, NULL, 0))
    {
        sql_server(thd->host, mysql_error(mysql), mysql_errno(mysql));
        goto err;
    } else
    {
        while (1)
        {
            if (mysql_real_query(mysql, select, strlen(select)))
            {
                sql_server(thd->host, mysql_error(mysql), mysql_errno(mysql));
            } else
            {
                res = mysql_store_result(mysql); // store query result
                if (!res)
                {
                    sql_server(thd->host, mysql_error(mysql), mysql_errno(mysql));
                    continue;
                }
                if (!mysql_num_rows(res))
                {
                    error = mysql_real_query(mysql, sql_init, strlen(sql_init));
                    if (error)
                    {
                        sql_server(thd->host, mysql_error(mysql), mysql_errno(mysql));
                        continue;
                    }
                }
                mysql_free_result(res);
                if (mysql_real_query(mysql, update, strlen(update)))
                    sql_server(thd->host, mysql_error(mysql), mysql_errno(mysql));
            }
            sleep(INTERVAL);
        }
    }

err:
    if (mysql)
    {
        mysql_close(mysql);
        mysql = NULL;
    }
    return 1;
}

static void process_redis(NG_THD *thd)
{
    while (1)
    {
        redis_check(thd->host, thd->port, thd->pass);
        sleep(INTERVAL);
    }
    return;
}

void *en_thread(void *agc)
{
    pthread_mutex_lock(&mutex);
    NG_THD *thd_tmp = (NG_THD *) agc;
    NG_THD thd;
    sprintf(thd.db, "%s", thd_tmp->db);
    sprintf(thd.host, "%s", thd_tmp->host);
    sprintf(thd.pass, "%s", thd_tmp->pass);
    sprintf(thd.user, "%s", thd_tmp->user);
    thd.port = thd_tmp->port;
    thd.type = thd_tmp->type;
    pthread_mutex_unlock(&mutex);

    switch (thd.type)
    {
        case NG_PROXY:
            printf("case proxy\n");
            process(&thd);
            break;
        case NG_REDIS:
            printf("case redis\n");
            process_redis(&thd);
            break;
        case NG_MYSQL:
            printf("case mysql\n");
            break;
        default:
            break;
    }
    pthread_exit(NULL);
}

void m_init(void)
{
    /* global variables are initialized */
    m_global_config_file = NULL;
    m_general_config_dir = NULL;
    log_file = NULL;
    log_level = 0;
    max_thread_num = 0;
    polling_time = 0;

    /* lock initialized */
    pthread_mutex_init(&mutex, NULL);

    /* list table initialize */
    cnf_file_list = NULL;
    return;
}

static int parse_cmdline(int argc, char **argv)
{
    int opt;
    /* Parse command line */
    while ((opt = getopt(argc, argv, "f:")) != EOF)
    {
        switch (opt)
        {
            case 'f':
                m_global_config_file = (char *) malloc(strlen(optarg));
                if (NULL == m_global_config_file)
                    return 1;
                memset(m_global_config_file, 0, strlen(optarg));
                memcpy(m_global_config_file, optarg, strlen(optarg));
                break;
            case '?':
                printf("Unknown options\n");
                my_help();
                return 1;
            case ':':
                printf("Format error\n");
                my_help();
                return 1;
            default:
                printf("International error.\n");
                return 1;
        }
    }
    return 0;
}

int main(int argc, char **argv)
{
    pthread_t thread[MAX_HOSTS];
    NG_THD thd[MAX_HOSTS];

    int host = 0;

    printf(">>>>>>>>>>>>>>>>>%s\n ", argv[0]);
    m_init(); /* init all server variables */
    cnf_file_list_init(cnf_file_list);

    if (parse_cmdline(argc, argv)
            || m_global_file_parse(m_global_config_file))
        return 1;

    fprintf(stdout, "read all hosts:\n");
#if 0
    for (host = 0; host <= node; host++)
    {
        if (thd[host].type == NG_PROXY)
            fprintf(stdout, ".......... ...... id:%d\thost[proxy]:%s, user:%s, pass:%s, port:%d, db:%s\n",
                host, thd[host].host, thd[host].user, thd[host].pass, thd[host].port, thd[host].db);
        if (thd[host].type == NG_REDIS)
            fprintf(stdout, ".......... ...... id:%d\thost[redis]:%s, user:%s, pass:%s, port:%d, db:%s\n",
                host, thd[host].host, thd[host].user, thd[host].pass, thd[host].port, thd[host].db);
        if (thd[host].type == NG_MYSQL)
            fprintf(stdout, ".......... ...... id:%d\thost[mysql]:%s, user:%s, pass:%s, port:%d, db:%s\n",
                host, thd[host].host, thd[host].user, thd[host].pass, thd[host].port, thd[host].db);
    }
    fprintf(stdout, "\nCreate monitor thread...\n");

    daemon(0, 0);
    for (host = 0; host <= node && host < MAX_HOSTS; host++)
    {
        if (pthread_create(&thread[host], NULL, en_thread, &thd[host]))
            fprintf(stderr, "Thread %d for %s create failed\n", host, thd[host].host);
    }

    fprintf(stdout, "Thread count:%d\n", host);
    /* The end */
    for (host--; host >= 0; host--)
        pthread_join(thread[host], NULL);
#endif

    return 0;
}
